﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.QuestBase
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using Helpers;
using System.Collections.Generic;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.GameMenus;
using TaleWorlds.CampaignSystem.Overlay;
using TaleWorlds.CampaignSystem.Settlements.Locations;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.ObjectSystem;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem
{
  public abstract class QuestBase : MBObjectBase
  {
    [SaveableField(100)]
    private QuestBase.QuestStates _questState;
    protected DialogFlow OfferDialogFlow;
    protected DialogFlow DiscussDialogFlow;
    protected DialogFlow QuestCharacterDialogFlow;
    [SaveableField(102)]
    private MBList<QuestTaskBase> _taskList;
    [SaveableField(103)]
    private readonly MBList<JournalLog> _journalEntries;
    [SaveableField(106)]
    private Hero _questGiver;
    [SaveableField(107)]
    public readonly int RewardGold;

    protected override void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      base.AutoGeneratedInstanceCollectObjects(collectedObjects);
      collectedObjects.Add((object) this._taskList);
      collectedObjects.Add((object) this._journalEntries);
      collectedObjects.Add((object) this._questGiver);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this.QuestDueTime, collectedObjects);
    }

    internal static object AutoGeneratedGetMemberValueQuestDueTime(object o)
    {
      return (object) ((QuestBase) o).QuestDueTime;
    }

    internal static object AutoGeneratedGetMemberValueIsTrackEnabled(object o)
    {
      return (object) ((QuestBase) o).IsTrackEnabled;
    }

    internal static object AutoGeneratedGetMemberValueRewardGold(object o)
    {
      return (object) ((QuestBase) o).RewardGold;
    }

    internal static object AutoGeneratedGetMemberValue_questState(object o)
    {
      return (object) ((QuestBase) o)._questState;
    }

    internal static object AutoGeneratedGetMemberValue_taskList(object o)
    {
      return (object) ((QuestBase) o)._taskList;
    }

    internal static object AutoGeneratedGetMemberValue_journalEntries(object o)
    {
      return (object) ((QuestBase) o)._journalEntries;
    }

    internal static object AutoGeneratedGetMemberValue_questGiver(object o)
    {
      return (object) ((QuestBase) o)._questGiver;
    }

    [SaveableProperty(101)]
    public CampaignTime QuestDueTime { get; protected set; }

    public MBReadOnlyList<QuestTaskBase> TaskList => (MBReadOnlyList<QuestTaskBase>) this._taskList;

    public MBReadOnlyList<JournalLog> JournalEntries
    {
      get => (MBReadOnlyList<JournalLog>) this._journalEntries;
    }

    [SaveableProperty(104)]
    public bool IsTrackEnabled { get; private set; }

    public bool IsOngoing => this._questState == QuestBase.QuestStates.Ongoing;

    public bool IsFinalized => this._questState == QuestBase.QuestStates.Finalized;

    public bool IsThereDiscussDialogFlow => this.DiscussDialogFlow != null;

    public Hero QuestGiver
    {
      get => this._questGiver;
      private set => this._questGiver = value;
    }

    public abstract TextObject Title { get; }

    public abstract bool IsRemainingTimeHidden { get; }

    public virtual int RelationshipChangeWithQuestGiver { get; protected set; }

    public virtual bool IsSpecialQuest => false;

    protected abstract void SetDialogs();

    protected QuestBase(string questId, Hero questGiver, CampaignTime duration, int rewardGold)
      : base(questId)
    {
      this.QuestGiver = questGiver;
      this.QuestDueTime = duration;
      this.IsTrackEnabled = true;
      this.RewardGold = rewardGold;
      this._taskList = new MBList<QuestTaskBase>();
      this._journalEntries = new MBList<JournalLog>();
    }

    public void StartQuest()
    {
      this._questState = QuestBase.QuestStates.Ongoing;
      this.OnStartQuest();
      this.RegisterEvents();
      MapEventHelper.OnConversationEnd();
      if (this.QuestGiver != null && !Campaign.Current.QuestManager.TrackedObjects.ContainsKey((ITrackableCampaignObject) this.QuestGiver))
        Campaign.Current.QuestManager.AddTrackedObjectForQuest((ITrackableCampaignObject) this.QuestGiver, this);
      CampaignEventDispatcher.Instance.OnQuestStarted(this);
    }

    public void CompleteQuestWithSuccess()
    {
      this.OnCompleteWithSuccess();
      this.FinalizeQuest();
      CampaignEventDispatcher.Instance.OnQuestCompleted(this, QuestBase.QuestCompleteDetails.Success);
      this.AfterFinalize();
    }

    public void CompleteQuestWithTimeOut(TextObject timeOutLog = null)
    {
      bool completeWithSuccess = false;
      bool doNotResolveTheQuest = false;
      this.OnBeforeTimedOut(ref completeWithSuccess, ref doNotResolveTheQuest);
      if (doNotResolveTheQuest)
        return;
      if (!completeWithSuccess)
      {
        if (timeOutLog != null)
          this.AddLog(timeOutLog);
        this.OnTimedOut();
        this.FinalizeQuest();
        CampaignEventDispatcher.Instance.OnQuestCompleted(this, QuestBase.QuestCompleteDetails.Timeout);
        this.AfterFinalize();
      }
      else
        this.CompleteQuestWithSuccess();
    }

    public void CompleteQuestWithFail(TextObject cancelLog = null)
    {
      if (cancelLog != null)
        this.AddLog(cancelLog);
      this.OnFailed();
      this.FinalizeQuest();
      CampaignEventDispatcher.Instance.OnQuestCompleted(this, QuestBase.QuestCompleteDetails.Fail);
      this.AfterFinalize();
    }

    public void CompleteQuestWithBetrayal(TextObject betrayLog = null)
    {
      if (betrayLog != null)
        this.AddLog(betrayLog);
      this.OnBetrayal();
      this.FinalizeQuest();
      CampaignEventDispatcher.Instance.OnQuestCompleted(this, QuestBase.QuestCompleteDetails.FailWithBetrayal);
      this.AfterFinalize();
    }

    public void CompleteQuestWithCancel(TextObject cancelLog = null)
    {
      if (cancelLog != null)
        this.AddLog(cancelLog);
      this.OnCanceled();
      this.FinalizeQuest();
      CampaignEventDispatcher.Instance.OnQuestCompleted(this, QuestBase.QuestCompleteDetails.Cancel);
      this.AfterFinalize();
    }

    private void FinalizeQuest()
    {
      foreach (QuestTaskBase task in (List<QuestTaskBase>) this._taskList)
      {
        if (task.IsActive)
          task.Finish(QuestTaskBase.FinishStates.Cancel);
      }
      this._questState = QuestBase.QuestStates.Finalized;
      this.OnFinalize();
      this.ClearRelatedFields();
      this.OfferDialogFlow = (DialogFlow) null;
      this.DiscussDialogFlow = (DialogFlow) null;
      this.QuestCharacterDialogFlow = (DialogFlow) null;
      Campaign.Current.QuestManager.OnQuestFinalized(this);
    }

    private void AfterFinalize() => this.RemoveAllTrackedObjects();

    protected void InitializeQuestOnCreation() => this.AddDialogs();

    public void InitializeQuestOnLoadWithQuestManager()
    {
      this.RegisterEvents();
      this.InitializeQuestOnGameLoad();
      this.AddDialogs();
    }

    internal void HourlyTickWithQuestManager() => this.HourlyTick();

    protected void AddTask(QuestTaskBase task)
    {
      this._taskList.Add(task);
      task.SetReferences();
    }

    protected virtual TextObject TargetHeroDisappearedLogText
    {
      get
      {
        return new TextObject("{=ZfRmHMJJ}{QUEST_TARGET.LINK} has lost the struggle against {?QUEST_TARGET.GENDER}her{?}his{\\?} rivals and decided to left the realm. Your agreement with {QUEST_GIVER.LINK} has been canceled and your service is no longer needed to solve the issue.");
      }
    }

    protected virtual TextObject TargetHeroDiedLogText
    {
      get
      {
        return new TextObject("{=WKIqnKtu}{QUEST_TARGET.LINK} has died and your agreement with {QUEST_GIVER.LINK} has been canceled. Your service is no longer needed to solve the issue.");
      }
    }

    public JournalLog AddLog(TextObject text, bool hideInformation = false)
    {
      JournalLog journalLog = new JournalLog(CampaignTime.Now, text);
      this._journalEntries.Add(journalLog);
      CampaignEventDispatcher.Instance.OnQuestLogAdded(this, hideInformation);
      return journalLog;
    }

    public JournalLog AddDiscreteLog(
      TextObject text,
      TextObject taskName,
      int currentProgress,
      int targetProgress,
      TextObject shortText = null,
      bool hideInformation = false)
    {
      JournalLog journalLog = new JournalLog(CampaignTime.Now, text, taskName, currentProgress, targetProgress, LogType.Discreate);
      this._journalEntries.Add(journalLog);
      CampaignEventDispatcher.Instance.OnQuestLogAdded(this, hideInformation);
      return journalLog;
    }

    public JournalLog AddTwoWayContinuousLog(
      TextObject text,
      TextObject taskName,
      int currentProgress,
      int range,
      bool hideInformation = false)
    {
      JournalLog journalLog = new JournalLog(CampaignTime.Now, text, taskName, currentProgress, range, LogType.TwoWayContinuous);
      this._journalEntries.Add(journalLog);
      CampaignEventDispatcher.Instance.OnQuestLogAdded(this, hideInformation);
      return journalLog;
    }

    protected void RemoveLog(JournalLog logToRemove)
    {
      if (this._journalEntries.Contains(logToRemove))
        this._journalEntries.Remove(logToRemove);
      else
        Debug.FailedAssert("Quest log requested to be removed cant be found.", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\QuestBase.cs", nameof (RemoveLog), 276);
    }

    protected void UpdateQuestTaskStage(JournalLog questLog, int currentProgress)
    {
      foreach (JournalLog journalEntry in (List<JournalLog>) this._journalEntries)
      {
        if (journalEntry == questLog)
          journalEntry.UpdateCurrentProgress(currentProgress);
      }
    }

    public virtual GameMenuOption.IssueQuestFlags IsLocationTrackedByQuest(Location location)
    {
      return GameMenuOption.IssueQuestFlags.None;
    }

    public virtual int GetCurrentProgress() => -1;

    public virtual int GetMaxProgress() => 1;

    public override string ToString() => this.StringId;

    public virtual string GetPrefabName() => "bd_target_board_2";

    private void AddDialogs()
    {
      if (this.OfferDialogFlow != null)
        Campaign.Current.ConversationManager.AddDialogFlow(this.OfferDialogFlow, (object) this);
      if (this.DiscussDialogFlow != null)
        Campaign.Current.ConversationManager.AddDialogFlow(this.DiscussDialogFlow, (object) this);
      if (this.QuestCharacterDialogFlow == null)
        return;
      Campaign.Current.ConversationManager.AddDialogFlow(this.QuestCharacterDialogFlow, (object) this);
    }

    private void ClearRelatedFields()
    {
      CampaignEventDispatcher.Instance.RemoveListeners((object) this);
      foreach (object task in (List<QuestTaskBase>) this._taskList)
        CampaignEventDispatcher.Instance.RemoveListeners(task);
      Campaign.Current.ConversationManager.RemoveRelatedLines((object) this);
      Campaign.Current.GameMenuManager.RemoveRelatedGameMenus((object) this);
      Campaign.Current.GameMenuManager.RemoveRelatedGameMenuOptions((object) this);
    }

    private void RemoveAllTrackedObjects()
    {
      Campaign.Current.QuestManager.RemoveAllTrackedObjectsForQuest(this);
    }

    public void AddTrackedObject(ITrackableCampaignObject trackedObject)
    {
      Campaign.Current.QuestManager.AddTrackedObjectForQuest(trackedObject, this);
      if (!this.IsTrackEnabled)
        return;
      Campaign.Current.VisualTrackerManager.RegisterObject(trackedObject);
    }

    public void RemoveTrackedObject(ITrackableCampaignObject trackedObject)
    {
      Campaign.Current.QuestManager.RemoveTrackedObjectForQuest(trackedObject, this);
    }

    public bool IsTracked(ITrackableCampaignObject o)
    {
      return Campaign.Current.QuestManager.TrackedObjects.ContainsKey(o) && Campaign.Current.QuestManager.TrackedObjects[o].Contains(this);
    }

    public void ToggleTrackedObjects()
    {
      this.IsTrackEnabled = !this.IsTrackEnabled;
      List<ITrackableCampaignObject> trackedObjectsOfAquest = Campaign.Current.QuestManager.GetAllTrackedObjectsOfAQuest(this);
      if (this.IsTrackEnabled)
      {
        foreach (ITrackableCampaignObject trackableCampaignObject in trackedObjectsOfAquest)
          Campaign.Current.VisualTrackerManager.RegisterObject(trackableCampaignObject);
      }
      else
      {
        foreach (ITrackableBase trackableBase in trackedObjectsOfAquest)
          Campaign.Current.VisualTrackerManager.RemoveTrackedObject(trackableBase);
      }
    }

    public void AddGameMenu(
      string menuId,
      TextObject menuText,
      OnInitDelegate initDelegate,
      GameOverlays.MenuOverlayType overlay = GameOverlays.MenuOverlayType.None,
      GameMenu.MenuFlags menuFlags = GameMenu.MenuFlags.None)
    {
      GameMenu gameMenu = new GameMenu(menuId);
      gameMenu.Initialize(menuText, initDelegate, overlay, menuFlags, (object) this);
      Campaign.Current.GameMenuManager.AddGameMenu(gameMenu);
    }

    public void AddGameMenuOption(
      string menuId,
      string optionId,
      TextObject optionText,
      GameMenuOption.OnConditionDelegate condition,
      GameMenuOption.OnConsequenceDelegate consequence,
      bool Isleave = false,
      int index = -1)
    {
      (Campaign.Current.GameMenuManager.GetGameMenu(menuId) ?? throw new KeyNotFoundException()).AddOption(optionId, optionText, condition, consequence, index, Isleave, relatedObject: (object) this);
    }

    public void ChangeQuestDueTime(CampaignTime questDueTime) => this.QuestDueTime = questDueTime;

    protected abstract void InitializeQuestOnGameLoad();

    protected abstract void HourlyTick();

    protected virtual void RegisterEvents()
    {
    }

    protected virtual void OnStartQuest()
    {
    }

    protected virtual void OnCompleteWithSuccess()
    {
    }

    protected virtual void OnFinalize()
    {
    }

    public virtual void OnFailed()
    {
    }

    protected virtual void OnTimedOut()
    {
    }

    protected virtual void OnBeforeTimedOut(
      ref bool completeWithSuccess,
      ref bool doNotResolveTheQuest)
    {
    }

    protected virtual void OnBetrayal()
    {
    }

    public virtual void OnCanceled()
    {
    }

    public virtual bool QuestPreconditions() => false;

    public virtual void OnHeroCanHaveQuestOrIssueInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanMarryInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanLeadPartyInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanHavePartyRoleOrBeGovernorInfoIsRequested(
      Hero hero,
      ref bool result)
    {
    }

    public virtual void OnHeroCanDieInfoIsRequested(
      Hero hero,
      KillCharacterAction.KillCharacterActionDetail causeOfDeath,
      ref bool result)
    {
      result = !hero.IsNotable || hero != this.QuestGiver;
    }

    public virtual void OnHeroCanBecomePrisonerInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanBeSelectedInInventoryInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanMoveToSettlementInfoIsRequested(Hero hero, ref bool result)
    {
    }

    internal enum QuestStates
    {
      Ongoing,
      Finalized,
    }

    public enum QuestCompleteDetails
    {
      Invalid,
      Success,
      Cancel,
      Fail,
      Timeout,
      FailWithBetrayal,
    }
  }
}
